/*************************************************************************
    > File Name: 4.epoll_server_2.c
    > Author: Ykk
    > Mail: 3393579535@qq.com 
    > Created Time: 2023年05月27日 星期六 10时29分30秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/epoll.h>
#include"network_utils.h"

#define IP "192.168.152.129"
#define PORT 8888
#define SIZE 1024

struct information
{	
    int fd;
	uint32_t events;
	u_int32_t s_addr;//ip
	u_int16_t sin_port;//port
};

int main(int argc,char *argv[])
{
	//创建套接字 绑定
	int lfd = tcp4bind(PORT,IP);
	//监听
	Listen(lfd,128);
	//创建树
	int epfd = epoll_create(1);
	//将lfd上树
	struct information *info = malloc(sizeof(struct information));
	if(info == NULL)
	{
		perror("");
		exit(1);
	}
	int events = EPOLLIN;
	info->fd = lfd;
	info->events = events;

	struct epoll_event ev = {
		.events = events,
		.data.ptr = info,
	};

	if(epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ev) == -1)
	{
		perror("epoll_ctl");
		exit(1);
	}

	struct epoll_event evs[SIZE];
	//while监听
	while(1)
	{
		int nread = epoll_wait(epfd,evs,SIZE,-1);
		if(nread < 0)
		{
			perror("epoll_wait");
			break;
		}
		else if(nread == 0)
		{
			continue;
		}
		else//有文件描述符变化
		{	
			for(int i = 0;i < nread;i++)
			{
				struct information *inf;
				inf = evs[i].data.ptr;
				//判断lfd变化，并且是读事件变化
				if(inf->fd == lfd && evs[i].events&EPOLLIN)
				{
					char ip[16] = "";
					struct sockaddr_in cliaddr;
					socklen_t len = sizeof(cliaddr);
					int cfd = Accept(lfd,(struct sockaddr *)&cliaddr,&len);
					inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16);
					printf("new client %s  %d\n",ip,ntohs(cliaddr.sin_port));

					//将cfd上树
					struct information *new_inf = malloc(sizeof(struct information));
                    if (new_inf == NULL) {
                        perror("");
                        exit(1);
                    }
					new_inf->fd = cfd;
				    new_inf->s_addr = cliaddr.sin_addr.s_addr;
					new_inf->sin_port = cliaddr.sin_port;
					new_inf->events = EPOLLIN;
					struct epoll_event ev = {
                        .events = EPOLLIN,
                        .data.ptr = new_inf,
                    };
					if(epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev) == -1)
					{
						perror("epoll_ctl");
                        close(cfd);
                        free(new_inf);
                        continue;
					}
				}
				else if(evs[i].events & EPOLLIN)//cfd变化，而且是读事件变化
				{
					
					char buf[SIZE] = "";
				    int n = read(inf->fd,buf,sizeof(buf));
					if(n < 0)
					{
						perror("read");
						epoll_ctl(epfd,EPOLL_CTL_DEL,inf->fd,&evs[i]);
					}
					else if(n == 0)//客户端关闭
					{
						char ip[16] = "";
						inet_ntop(AF_INET,&inf->s_addr,ip,16);
						printf("client %s  %d   close\n",ip,ntohs(inf->sin_port));
						epoll_ctl(epfd,EPOLL_CTL_DEL,inf->fd,&evs[i]);//下树
						close(inf->fd);//将cfd关闭
						free(inf);
					}
					else
					{
						char ip[16] = "";
						char serverbuf[SIZE+9]="server==>";
						inet_ntop(AF_INET,&inf->s_addr,ip,16);
						printf("client %s  %d==> ",ip,ntohs(inf->sin_port));
						printf("%s\n",buf);
						strcat(serverbuf,buf);
						//write(inf->fd,serverbuf,n+9);
						int nwrote = 0;
                        while (nwrote < n + 9)
						{
                            int n = write(inf->fd, serverbuf + nwrote, n + 9 - nwrote);
                            if (n == -1) 
							{
                                perror("write");
                                epoll_ctl(epfd, EPOLL_CTL_DEL, inf->fd, &evs[i]);
                                break;
                            }
                            nwrote += n;
                        }
					}
				}
			}
		}
	}
	return 0;
}
